/*--------------------------------------------------------------------------------
 * Adaptive Intelligence - Foundation Framework Class Library
 * Version 2.00
 * 
 * Simple Cryptography Class
 *      Provides a static class for performing cryptographic operations based on 
 * simple parameters.
 *------------------------------------------------------------------------------*/

/*--------------------------------------------------------------------------------
 * System Imports
 *------------------------------------------------------------------------------*/
using System;
using System.IO;

namespace Adaptive.Foundation.Security
{
    /// <summary>
    /// Provides a static class for performing cryptographic operations based on 
    /// simple parameters.
    /// </summary>
    public static class SimpleCrypt
    {
        private const int DEF_MAX_MEMORY = 268435455;

        /*--------------------------------------------------------------------------------
         * Public Static/Shared Properties
         *------------------------------------------------------------------------------*/
        #region Public Static/Shared Properties
        #endregion

        /*--------------------------------------------------------------------------------
         * Public Static/Shared Methods / Functions
         *------------------------------------------------------------------------------*/
        #region Public Static/Shared Methods / Functions
        /// <summary>
        /// Performs an RSA encryption on the supplied data.
        /// </summary>
        /// <param name="dataToEncrypt">
        /// The data to be encrypted.
        /// </param>
        /// <returns>
        /// A byte array containing the encrypted data content.
        /// </returns>
        public static byte[] RsaEncrypt(byte[] dataToEncrypt)
        {
            CryptographicOperation operation = null;        //Operation to perform.
            RsaCryptoDevice device = null;                  //Cryptographic implementation.
            byte[] returnValue = null;                      //Return value.

            //Create the operation object(s).
            operation = new CryptographicOperation();
            operation.Algorithm = CryptographicAlgorithm.Rsa;
            operation.OperationType = CryptographicOperationType.Encrypt;
            operation.SourceData = new MemoryStream(dataToEncrypt);
            device = new RsaCryptoDevice();

            //Try to encrypt the data.
            if (device.PerformOperation(operation))
            {
                returnValue = ToArray(operation.Result.ResultData);
            }
            device.Dispose();
            operation.Dispose();

            return returnValue;
        }
        /// <summary>
        /// Performs an RSA decryption on the supplied data.
        /// </summary>
        /// <param name="dataToDecrypt">
        /// The data to be decrypted.
        /// </param>
        /// <returns>
        /// A byte array containing the decrypted data content.
        /// </returns>
        public static byte[] RsaDecrypt(byte[] dataToDecrypt)
        {
            CryptographicOperation operation = null;        //Operation to perform.
            RsaCryptoDevice device = null;                  //Cryptographic implementation.
            byte[] returnValue = null;                      //Return value.

            //Create the operation object(s).
            operation = new CryptographicOperation();
            operation.Algorithm = CryptographicAlgorithm.Rsa;
            operation.OperationType = CryptographicOperationType.Decrypt;
            operation.SourceData = new MemoryStream(dataToDecrypt);
            device = new RsaCryptoDevice();

            //Try to encrypt the data.
            if (device.PerformOperation(operation))
            {
                returnValue = ToArray(operation.Result.ResultData);
            }
            device.Dispose();
            operation.Dispose();

            return returnValue;
        }
        /// <summary>
        /// Performs a symmetric-algorithm encryption on the supplied data.
        /// </summary>
        /// <param name="algorithm">
        /// A <see cref="CryptographicAlgorithm"/> enumerated value indicating the encryption item to 
        /// use.
        /// </param>
        /// <param name="key">A byte array containing the encryption key.</param>
        /// <param name="iv">A byte array containing the initialization vector.</param>
        /// <param name="dataToEncrypt">The data to be encrypted.</param>
        /// <returns>
        /// A byte array containing the encrypted data.
        /// </returns>
        public static byte[] SymmetricEncrypt(CryptographicAlgorithm algorithm, byte[] key, byte[] iv, byte[] dataToEncrypt)
        {
            SymmetricCryptographicDeviceBase encryptor = null;      //Encryption device.
            CryptographicDeviceBase devicePtr = null;               //Type pointer.
            CryptographicOperation operation = null;                //Operation to be performed.
            byte[] returnValue = null;                              //Return value.

            devicePtr = CreateDevice(algorithm);
            if (!(devicePtr is SymmetricCryptographicDeviceBase))
                throw new InvalidAlgorithmException();
            else
            {
                //Re-cast the item.
                encryptor = (SymmetricCryptographicDeviceBase)devicePtr;

                operation = new CryptographicOperation();
                operation.Algorithm = algorithm;
                operation.OperationType = CryptographicOperationType.Encrypt;
                operation.SourceData = new MemoryStream(dataToEncrypt);

                //Perform the operation.
                encryptor.Key = key;
                encryptor.IV = iv;
                if (encryptor.PerformOperation(operation))
                {
                    returnValue = ToArray(operation.Result.ResultData);
                }

                encryptor.Dispose();
                operation.Dispose();
            }

            return returnValue;

        }
        /// <summary>
        /// Performs a symmetric-algorithm decryption on the supplied data.
        /// </summary>
        /// <param name="algorithm">
        /// A <see cref="CryptographicAlgorithm"/> enumerated value indicating the encryption item to 
        /// use.
        /// </param>
        /// <param name="key">A byte array containing the decryption key.</param>
        /// <param name="iv">A byte array containing the initialization vector.</param>
        /// <param name="dataToDecrypt">The data to be decrypted.</param>
        /// <returns>
        /// A byte array containing the decrypted data.
        /// </returns>
        public static byte[] SymmetricDecrypt(CryptographicAlgorithm algorithm, byte[] key, byte[] iv, byte[] dataToDecrypt)
        {
            SymmetricCryptographicDeviceBase decryptor = null;      //Encryption device.
            CryptographicDeviceBase devicePtr = null;               //Type pointer.
            CryptographicOperation operation = null;                //Operation to be performed.
            byte[] returnValue = null;                              //Return value.

            devicePtr = CreateDevice(algorithm);
            if (!(devicePtr is SymmetricCryptographicDeviceBase))
                throw new InvalidAlgorithmException();
            else
            {
                //Re-cast the item.
                decryptor = (SymmetricCryptographicDeviceBase)devicePtr;

                operation = new CryptographicOperation();
                operation.Algorithm = algorithm;
                operation.OperationType = CryptographicOperationType.Decrypt;
                operation.SourceData = new MemoryStream(dataToDecrypt);

                //Perform the operation.
                decryptor.Key = key;
                decryptor.IV = iv;
                if (decryptor.PerformOperation(operation))
                {
                    returnValue = ToArray(operation.Result.ResultData);
                }

                decryptor.Dispose();
                operation.Dispose();
            }

            return returnValue;

        }
        /// <summary>
        /// Creates a cryptographic device instance base on the specified algorithm.
        /// </summary>
        /// <param name="algorithm">
        /// A <see cref="CryptographicAlgorithm"/> enumerated value indicating the encryption item to 
        /// use.
        /// </param>
        /// <returns>
        /// A <see cref="CryptographicDeviceBase"/> implementation for the specified algorithm.
        /// </returns>
        public static CryptographicDeviceBase CreateDevice(CryptographicAlgorithm algorithm)
        {
            CryptographicDeviceBase returnValue = null;             //Return value.

            switch (algorithm)
            {
                case CryptographicAlgorithm.Aes:
                    returnValue = new AesCryptoDevice();
                    break;

                case CryptographicAlgorithm.Des:
                    returnValue = new DesCryptoDevice();
                    break;

                case CryptographicAlgorithm.MultiAes:
                    returnValue = new AesCryptoDevice();
                    break;

                case CryptographicAlgorithm.Rc2:
                    returnValue = new Rc2CryptoDevice();
                    break;

                case CryptographicAlgorithm.Rsa:
                    returnValue = new RsaCryptoDevice();
                    break;

                case CryptographicAlgorithm.TripleDes:
                    returnValue = new TripleDesCryptoDevice();
                    break;

            }
            return returnValue;
        }
        #endregion

        /*--------------------------------------------------------------------------------
         * Private Static/Shared Methods / Functions
         *------------------------------------------------------------------------------*/
        #region Private Static/Shared Methods / Functions
        /// <summary>
        /// Converts a stream to a byte array.
        /// </summary>
        /// <param name="source">
        /// The Stream instance to be read.
        /// </param>
        /// <returns>
        /// A byte array.
        /// </returns>
        private static byte[] ToArray(Stream source)
        {
            BinaryReader reader = null;         //Data reader.
            byte[] returnValue = null;          //Return value.
            long maxSize = 0;                   //Maximum data size.

            if (source != null)
            {
                //Set maximum size.
                if (source.Length < DEF_MAX_MEMORY)
                    maxSize = source.Length;
                else
                    maxSize = DEF_MAX_MEMORY;

                //Read data.
                reader = new BinaryReader(source);
                source.Seek(0, SeekOrigin.Begin);
                returnValue = reader.ReadBytes((int)maxSize);
                reader = null;
            }

            return returnValue;
        }
        #endregion

    }
}
